//
//  PongFieldController.mm
//
//  Created by Jonathan Saggau on 2007-08-09.
//  Copyright (c) 2007 __MyCompanyName__. All rights reserved.
//

#import "PongFieldController.h"
#import "PongField.h"
#import "ServerController.h"
#import "ClientController.h"
#import "PongPrefs.h"
#import "PongGeometry.h"
#import "unistd.h"
#import "Common.h"

extern CGRect thumbRect;
extern PongPrefs *sharedPongPrefs;

@implementation PongFieldController

-(id)initWithFieldRect:(CGRect) fieldRect;
{
	self = [super init];
	if (nil != self)
	{
		LogMethod();
		NSLog(@"fieldRect = {{%f, %f},{%f, %f}}", fieldRect.origin.x, fieldRect.origin.y, fieldRect.size.width, fieldRect.size.height);
		field = [[PongField alloc] initWithFieldRect:fieldRect];
		rotation = 0;
        updating = NO;
        stepX = stepY = 0.0f;
	}
	return self;
}

-(void)serverControllerDidBork:(NSException *)e
{
	LogMethod();
	[self endGame];
	
	if(nil != delegate && [delegate respondsToSelector:@selector(serverControllerDidBork:)])
		[delegate performSelector:@selector(serverControllerDidBork:) withObject:e];
}

-(void)clientControllerDidBork:(NSException *)e
{
	LogMethod();
	[self endGame];
	
	if(nil != delegate && [delegate respondsToSelector:@selector(clientControllerDidBork:)])
		[delegate performSelector:@selector(clientControllerDidBork:) withObject:e];
}

-(void)clientControllerIsConnecting
{
	if(nil != delegate && [delegate respondsToSelector:@selector(clientControllerIsConnecting)])
		[delegate performSelector:@selector(clientControllerIsConnecting)];
}

-(void)clientControllerFinishedConnecting
{
	if(nil != delegate && [delegate respondsToSelector:@selector(clientControllerIsConnecting)])
		[delegate performSelector:@selector(clientControllerFinishedConnecting)];
}

-(void)initClient
{
	LogMethod();

	clientController = [[ClientController alloc] init];

	@try {
		[self clientControllerIsConnecting];
		[clientController connect];
    }
    @catch (NSException * e) {
		[self clientControllerDidBork:e];
    }
    @finally {
		[self clientControllerFinishedConnecting];
    }
}

-(void)initServer
{
	LogMethod();
	serverController = [[ServerController alloc] init];
	[serverController setDelegate:self];
    [serverController startListening];
}

-(void)killServer
{
	LogMethod();
	
	if (nil == serverController)
	{
		NSLog(@"serverController is nil");
		return;
	}
	NSLog(@"serverController = %@", serverController);
		
	[serverController stopListening];
	[serverController release]; serverController = nil;
	sleep(1.0);
}

-(void)killClient
{
	LogMethod();
	
	if (nil == clientController)
	{
		NSLog(@"clientController is nil");
		return;
	}
	NSLog(@"clientController = %@", clientController);
	[clientController disconnect];
	NSLog(@"releasing clientController %@", clientController);
	[clientController release]; clientController = nil;
	sleep(1.0);
}

-(void)dealloc
{
	LogMethod();
	[field release]; field = nil;		
	[self killClient];
	[self killServer];
	[super dealloc];
}

-(void)beginNewGame
{
	LogMethod();
	if ([serverController currentPort] != (unsigned short) [sharedPongPrefs port])	
	{
		NSLog(@"Server Port not same as prefs port; killing server");
		[self killServer];
	}	
		
	NSString *remoteClientHostName = [clientController remoteHostName];
	NSString *prefsHostName = [sharedPongPrefs hostName];
	if (![remoteClientHostName isEqualToString:prefsHostName] || ([clientController remotePort] != (unsigned short) [sharedPongPrefs port]))
	{
		NSLog(@"Client Port and/or host name not same as prefs; killing client");
		[self killClient];
	}

	if (nil == serverController)
	{
		NSLog(@"initializing server");
		[self initServer];
		sleep(1);
	}
	if (nil == clientController)
	{
		NSLog(@"initializing client");
		[self initClient];
		sleep(1);
	}
		
    CGRect fieldRect = [field fieldRect];
    CGRect ballRect;
    ballRect.size = CGSizeMake(10.0, 10.0);
    ballRect.origin.x = (fieldRect.size.height * 0.5) - (ballRect.size.height * 0.5);
    ballRect.origin.y = (fieldRect.size.width * 0.5) - (ballRect.size.width * 0.5);
    [field setBallRect:ballRect];
    
    stepX = ((float) ((random() % 100) + 50) * 0.01) * MOVEMENT_MULTIPLIER;
    stepY = MOVEMENT_MULTIPLIER;
    updating = YES;
    
    NSLog(@"New Game stepX = %f stepY = %f", stepX, stepY);
}

-(void)endGame
{
    //LogMethod();
    if(nil != delegate && [delegate respondsToSelector:@selector(gameDidEnd)])
        [delegate performSelector:@selector(gameDidEnd)];
}

-(void)bounce
{
    //LogMethod();
	if(nil != delegate && [delegate respondsToSelector:@selector(bounce)])
        [delegate performSelector:@selector(bounce)];
}

-(void)updateUserInteraction
{
    CGRect rightPaddleRect = [field rightPaddle];
	NSRect fieldNSRect = NSRectFromCGRect([field fieldRect]);
    
	if ((thumbRect.origin.x < rightPaddleRect.origin.x) && thumbRect.origin.x > 0.0)
		rightPaddleRect.origin.x -= PADDLE_STEP * MOVEMENT_MULTIPLIER;
	else if (thumbRect.origin.x > (rightPaddleRect.origin.x + rightPaddleRect.size.width))
		rightPaddleRect.origin.x += PADDLE_STEP * MOVEMENT_MULTIPLIER;
    
	if (4 == rotation)
		rightPaddleRect.origin.x += PADDLE_STEP * MOVEMENT_MULTIPLIER;
	else if (3 == rotation)
		rightPaddleRect.origin.x -= PADDLE_STEP * MOVEMENT_MULTIPLIER;
    
	//don't move if we're going off the screen
    if ((rightPaddleRect.origin.x < 0.0) || 
        ((rightPaddleRect.origin.x + rightPaddleRect.size.width) > (fieldNSRect.origin.x + fieldNSRect.size.width)))
        return;
    
    [field setRightPaddle:rightPaddleRect];
}

-(void)updatePhysics
{
    //Here is where we move stuff.
    
    if (!updating)
        return;
	CGRect ballRect = [[self field] ballRect];
    CGRect fieldRect = [[self field] fieldRect];
    CGRect leftPaddle = [[self field] leftPaddle];
    CGRect rightPaddle = [[self field] rightPaddle];
    float maxX = fieldRect.origin.x + fieldRect.size.width - ballRect.size.width;
    float maxY = fieldRect.origin.y + fieldRect.size.height - ballRect.size.height;
    float minX = fieldRect.origin.x;
    float minY = fieldRect.origin.y;
    
	ballRect.origin.y += stepY;
    ballRect.origin.x += stepX;
    if(NSIntersectsRect(NSRectFromCGRect(ballRect), NSRectFromCGRect(leftPaddle)) || 
       NSIntersectsRect(NSRectFromCGRect(ballRect), NSRectFromCGRect(rightPaddle)))
    {
        stepY *= -1; // switchDirection
		[self bounce];
    }
    if(ballRect.origin.x >= maxX || ballRect.origin.x <= minX)
    {
        stepX *= -1; // switchDirection
		[self bounce];
    }
    if (ballRect.origin.y >= maxY + ballRect.size.height)
    {
        updating = NO;
        int rightScore = [[self field] rightScore];
        [[self field] setRightScore:rightScore + 1];
        [self endGame];
        return;
    }
    if (ballRect.origin.y <= minY - ballRect.size.height)
    {
        updating = NO;
        int leftScore = [[self field] leftScore];
        [[self field] setLeftScore:leftScore + 1];
        [self endGame];
        return;
    }
    
	[[self field] setBallRect:ballRect];
}


-(void)updateAndSendClientMsg
{
	NSString *bigMessage;
	CGRect aRect = [field rightPaddle];
	NSString *rightPaddle = NSStringFromRect(NSRectFromCGRect(aRect));
	bigMessage = [NSString stringWithFormat:@"RP;%@%@", rightPaddle, PACKET_TAG];
	@try {
		[clientController send:bigMessage];
    }
    @catch (NSException * e) {
		[self clientControllerDidBork:e];
    }
    @finally {
        // <#statements#>
    }
}

- (void)updateInfoFromServer
{
	NSString *incomingMsg;
	// incomingMsg = [serverController messageReceived];
	
	@try {
		incomingMsg = [serverController messageReceived];
    }
    @catch (NSException * e) {
		[self serverControllerDidBork:e];
		return;
    }
    @finally {
        // <#statements#>
    }
	//NSLog(@"incomingMsg = %@", incomingMsg);
	
	if (IsEmpty(incomingMsg))
		return;
	
	NSArray *indivMsgs = [incomingMsg componentsSeparatedByString:@";"];
	NSString *eachMsg;
	NSString *eachMsgNext;
	CGRect aRect;
	int i;
	for (i = 0; i< ([indivMsgs count] - 1); i+=2)
	{
		eachMsg = [indivMsgs objectAtIndex:i];
		// NSLog(@"eachMsg = %@", eachMsg);
		eachMsgNext = [indivMsgs objectAtIndex:i+1];
		// NSLog(@"eachMsgNext = %@", eachMsgNext);
		if ([eachMsg isEqualToString:@"LP"])
		{
			// NSLog(@"LeftPaddle recd ");
			aRect = PongCGRectFromString(eachMsgNext);
			[field setLeftPaddle:aRect];
		}
        else if ([eachMsg isEqualToString:@"PB"])
		{
			// NSLog(@"BALL!!! recd");
			aRect = PongCGRectFromString(eachMsgNext);
			[field setBallRect:aRect];
		}
        else if ([eachMsg isEqualToString:@"BB"])
		{
			// NSLog(@"Bounce Message");
			[self bounce];
		}
        else if ([eachMsg isEqualToString:@"EG"])
		{	
			// NSLog(@"EndGame Message");
			[self endGame];
		}
		else
		{
			// NSLog(@"!!!!!!!!UNHANDLED!!!!!!");
		}
    }
}

-(void)update
{
	[[self field] setRightFinger:thumbRect.origin];
	[self updateUserInteraction];
	[self updatePhysics];
	
	[self updateAndSendClientMsg];
	[self updateInfoFromServer];    
}

-(PongField *)field;
{
	return field;
}

- setRotation:(int)rot;
{
	rotation = rot;
}

- (id)delegate
{
    return delegate; 
}
- (void)setDelegate:(id)aDelegate
{
	delegate = aDelegate;
}

@end
